/**
 * Created by 宝哥哥 on 17/4/29.
 The MIT License (MIT)
 Copyright (c) <year> <copyright holders>
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


/**
 * video适配模式代号
 **/
var FIXMODE = {
        fixWidth  : 1,//宽自适应，
        fixHeight : 2,//高自适应
        fixFree   : 3,//自由模式，自定义宽高
}
/**
 * video状态代号
 * @type {{Created: number, Loading: number, CanPlay: number, Loaded: number, Playing: number, Paused: number, PlayEnd: number, PlayError: number}}
 */
var VIDEOSTATUS = {
    Created      : 1,//创建成功，获取到视频长度和元数据
    Loading      : 2,//加载缓冲中
    CanPlay      : 3,//可播放状态（但不一定加载完成，主要依靠video.readyState来判断）
    Loaded       : 4,//完全加载完毕(暂时用不上，因为加载完太慢了)
    Playing      : 5,//播放中
    Paused       : 6, //播放暂停
    PlayEnd      : 7,//播放结束
    PlayError    : 8//播放失败(例如网络中断等原因)
}

/**
 *
 * @param parentDom             视频初始化所在的父元素
 * @param url                   视频地址
 * @param fixMode               暂时只有三种适配选择，1,宽自适应  2,高自适应 3,自由模式(自定义宽度，高度等比例缩放,但移动端不适用)
 * @param width                 视频播放器宽度
 * @param height                视频播放器高度
 * @constructor
 */
function VideoClass(parentDom,url,fixMode,width,height){
    var self = this;
    self._parentDom = parentDom;	    //video的父容器DOM对象
    self._fixMode = parseInt(fixMode);	//video的适配模式
    self._width = width;	            //video的适配模式为3时才有效，表示视频所设置的宽度
    self._end=0;                        //video加载时的缓冲区结束位置(其实就是已加载的视频时长，秒为单位)
    self.debug = false;                 //调试模式，默认关闭
    self.url = url;	                    //video的视频链接
    self.video;			                //video的DOM对象
    self.status = VIDEOSTATUS.Created;	//video的当前状态
    self.duration=0;		            //video的视频时长
    /**
     * 检查父元素是否合法
     */
    switch(typeof parentDom){
        case "string"://传入有效的父元素选择器
            self._parentDom = document.querySelector(parentDom);
            if(!self._parentDom){
                throw new Error("不是有效的父元素");
            }
            break;
        case "object"://传入有效的父元素对象
            if(!parentDom instanceof Element){
                throw new Error("不是有效的父元素");
            }
            self._parentDom = parentDom;
            break;
        default:
            throw new Error("不是有效的父元素");
    }
    /**
     * 检查地址是否有效
     */
    if(!self.url){
        throw new Error("不是有效的视频地址");
    }

    /**
     * 初始化一个video对象，并插入到父元素容器中
     */
    self.video = document.createElement("video");

    //先设置宽高为1px，进行视频隐藏，等初始化完成后，再放出
    // self._setClassbutes({
    //     "width":"1px",
    //     "height":"1px"
    // });
    self._setFixMode();
    //设置必要的属性
    self._setAttributes(
        {
            "src"						:self.url,
            "preload"					:"none",        //禁止了自动加载，由用户决定加载的时机
            "webkit-playsinline"		:"true",        //是ios 10中设置可以让视频在小窗内播放，也就是不是全屏播放
            "playsinline"				:"true",        //微信浏览器支持小窗内播放
            "x-webkit-airplay"			:"allow",       //这个属性应该是使此视频支持ios的AirPlay功能
            "x5-video-player-type"		:"h5",          //启用H5播放器,可以让视频全屏播放并不显示进度条，并且支持在视频上叠放任意元素，但在安卓上会有一下的闪屏.
            "x5-video-player-fullscreen":"true",        //全屏设置,它有两个属性值，ture和false，true支持全屏播放，false不支持全屏播放。
            "x5-video-orientation"		:"portraint",   //播放器支持的方向，landscape横屏，portraint竖屏，默认值为竖屏
        }
    );
    //把video插入到父容器
    self._parentDom.appendChild(self.video);
}
/**
 * 播放
 * @param playEndCallback       播放完毕回调
 * @param loadedCallback        加载完成后的回调
 */
VideoClass.prototype.play = function(playEndCallback,loadedCallback){
    var self = this;

    //如果有设置播放完成后的回调，则设置播放结束后的回调事件
    playEndCallback?self.video.addEventListener("ended",playEndCallback):"";

    //如果发现还没有加载，则开始加载，所以这里只会执行一次，之后再执行play也不会触发_load方法,而是直接执行video.play()
    if(self.status == VIDEOSTATUS.Created){
        console.log("触发加载");
        self._load(loadedCallback);
    }else{
        console.log("触发播放");
        self.video.play();      //开始播放视频
    }
}
/**
 * 暂停
 */
VideoClass.prototype.pause = function(){
    var self = this;
    if(self.video.paused===false){
        self.video.pause();
    }


}
/**
 * 停止
 */
VideoClass.prototype.stop = function(){
    var self = this;
    self.pause();                   //停止视频
    self.video.currentTime = 0;     //并设置当前时间为一开始，0秒
}
/**
 * 加载（因为安卓和PC都没办法很好的计算加载百分比，所以此方法只是个IOS下的玩具）
 * @param loadedCallback        加载完毕回调
 * @param progressCallback      加载中的回调
 * @private
 */

/**
 * 以时:分:秒的格式来获取视频时长
 * @returns {string}
 */
VideoClass.prototype.getFormatTime = function () {
    var self = this;
    var time = self.duration?self.duration:0;

    var h = parseInt(time/3600),
        m = parseInt(time%3600/60),
        s = parseInt(time%60);
    h = h < 10 ? "0"+h : h;
    m = m < 10 ? "0"+m : m;
    s = s < 10 ? "0"+s : s;

    return h+":"+m+":"+s;
}
/**
 * 初次加载，第一次play的时候会调用该方法
 * @param loadedCallback
 * @param progressCallback
 * @private
 */
VideoClass.prototype._load = function(loadedCallback,progressCallback){
    var self = this;
    self.video.load();                  //主动调用加载
    self.status = VIDEOSTATUS.Loading;  //修改状态为"加载中" 2
    self.video.play();                  //主动调用播放


    /**因为移动端下，视频还没开始播放的时候，会显示黑屏，所以我把视频真正出现的时机，推迟到当视频播放极小一段时间后，再出现，这样就有效避免黑屏出现**/
    var func = function(){
        // self._setFixMode();                 //重新设置正确的视频大小，并显示出来
        loadedCallback?loadedCallback():""; //加载完成的回调事件
    }
    var isAndroid = navigator.userAgent.match(/(Android)\s+([\d.]+)/) || navigator.userAgent.match(/Silk-Accelerated/) ? true : false;
    if(!isAndroid){
        var _timeupdateCallback = function(){
            self.video.removeEventListener("timeupdate",_timeupdateCallback);
            func();
        }
        self.video.addEventListener("timeupdate",_timeupdateCallback);
    }else{

        var _timeupdateCallback = function(){
            self.video.removeEventListener("progress",_timeupdateCallback);
            func();
        }
        self.video.addEventListener("progress",_timeupdateCallback);
    }


    /**获取视频的时长，此处有坑，必须在canplay方法里才能获取正确,并且只有在ios和PC才支持**/
    self.video.addEventListener("canplay",function(){
        self.duration = self.video.duration;
    })



    /**整段垮掉START，除了ios可以做到计算加载百分比，安卓没办法获取到视频时长和缓冲位置，而PC必须边播放边下载没办法做预加载，所以结论就是暂时没卵用*****/
    if(self.debug){

        //设置定时器，监听当前加载进度，加载完成就退出监听，并执行回调操作
        var timer = setInterval(
            function() {
                self._getEnd();
                console.log("=============================");
                console.log("视频状态:"+self.video.readyState);
                console.log("视频总长(秒):"+self.duration);
                console.log("视频总长(格式化):"+self.getFormatTime());
                console.log("当前播放进度:"+self.video.currentTime);
                console.log("缓冲结束位置:"+self._end);
                console.log("加载百分比:"+Math.floor(self._end/self.duration*100));


                var progress = Math.floor(self._end/self.duration*100);//计算加载百分比
                progressCallback?progressCallback(progress):'';//触发每次加载的回调

                if(self.video.readyState>3 && self.status<3){//当视频的readyState>3,表示加载了部分，并且自定义的视频状态在4以下
                    console.log("可以播放，但不一定加载完");
                    self.status = VIDEOSTATUS.CanPlay;       //修改视频状态为"可播放"   3
                }

                if(progress == 100 && self.status<4){
                    console.log("全部加载完毕");
                    self.status = VIDEOSTATUS.Loaded;       //修改视频状态为"加载完毕"    4
                    // clearInterval(timer);
                }
            }
        , 2000);
    }
    /**整段垮掉END，除了ios可以做到计算加载百分比，安卓没办法获取到视频时长和缓冲位置，而PC必须边播放边下载没办法做预加载，所以结论就是暂时没卵用***/


}
/**
 * 获取当前的缓冲区结束位置
 */
VideoClass.prototype._getEnd = function(){
    var self = this;
    try{
        self._end = self.video.buffered.end(0) || 0;
    }catch(e){
        self._end = 0;
    }
}
/**
 * 设置视频适配模式
 * @private
 */
VideoClass.prototype._setFixMode = function(){
    var self = this;
    var data = {};
    switch (self._fixMode){
        //判断是否传入有效的适配模式代号
        case 1:
            data = {
                "width":"100%",
                "height":"auto",
                "objectFit":"fill"          //解决Android的微信里面的上下有黑边
            };
            break;
        case 2:
            data = {
                "width":"auto",
                "height":"100%",
                "objectFit":"fill"          //解决Android的微信里面的左右有黑边
            };
            break;
        case 3:
            data = {
                "width":self._width+"px",
                "height":"auto"
                // ,"objectFit":"fill"          //解决Android的微信里面的上下有黑边
            };
            break;
        default:
            data = {
                "width":"100%",
                "height":"auto",
                "objectFit":"fill"          //解决Android的微信里面的上下有黑边
            };
            self._fixMode = 1;//默认用宽自适应
    }
    self._setClassbutes(data);
}
/**
 * 批量设置video属性
 * @param data
 * @private
 */
VideoClass.prototype._setAttributes = function(data){
    var self = this;
    for(var k in data){
        self.video.setAttribute(k,data[k]);
    }
}
/**
 * 批量设置video样式
 * @param data
 * @private
 */
VideoClass.prototype._setClassbutes = function(data){
    var self = this;
    for(var k in data){
        self.video.style[k]=data[k];
    }
}